﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Forms;
using HQLAddin.ConfigurationInspector;
using HQLAddin.Util;
using HqlIntellisense;
using HqlIntellisense.ConfigurationAbstraction;
using Microsoft.VisualStudio.Shell;

namespace HQLAddin.Intellisense
{
	[Export(typeof(IConfigurationDataProvider))]
	[PartCreationPolicy(CreationPolicy.Shared)]
	[Serializable]
	internal class ConfigurationProvider : IConfigurationDataProvider, IDisposable
	{
		private readonly IPathProvider pathProvider;
		private readonly IAppDomainProxy appDomainProxy;


		private IEnumerable<IPersistentClassInformation> classes;
		private IDictionary<string, string> imports;
		private readonly ITaskList errorProvider;
		private readonly IOutputPaneLogger outputPaneLogger;

		[ImportingConstructor]
		internal ConfigurationProvider(
			IBuildWatcher buildWatcher, 
			IPathProvider pathProvider,
			IAppDomainProxy appDomainProxy,
			SVsServiceProvider serviceProvider,
			IOutputPaneLogger outputPaneLogger)
			: this(buildWatcher, pathProvider, appDomainProxy, new TaskListWrapper( new ErrorListProvider(serviceProvider)), outputPaneLogger)
		{}

		public ConfigurationProvider(
			IBuildWatcher buildWatcher,
			IPathProvider pathProvider,
			IAppDomainProxy appDomainProxy,
			ITaskList taskList,
			IOutputPaneLogger outputPaneLogger)
		{
			this.pathProvider = pathProvider;
			this.appDomainProxy = appDomainProxy;
			errorProvider = taskList;
			this.outputPaneLogger = outputPaneLogger;
			buildWatcher.BuildSucced += BuildWatcherBuildSucced;
			BuildWatcherBuildSucced(this, EventArgs.Empty);
		}

		#region IConfigurationDataProvider Members

		public IPersistentClassInformation GetClassMapping(string path)
		{
			if (classes == null) return null;
			return classes.FirstOrDefault(c => c.ClassName == path);
		}

		public IPersistentClassInformation GetClassMapping(Type type)
		{
			throw new NotImplementedException();
		}

		public IDictionary<string, string> Imports
		{
			get { return imports ?? new Dictionary<string, string>(); }
		}

		#endregion

		private void BuildWatcherBuildSucced(object sender, EventArgs e)
		{
			var findPaths = pathProvider.FindPaths().ToArray();
			if (findPaths.Length == 0) return;
			classes = new List<IPersistentClassInformation>();
			imports = new Dictionary<string, string>();
			
			errorProvider.Clear();
			
			foreach (var path in findPaths)
			{
				try
				{
					var artifacts = appDomainProxy.GetArtifacts(path);
					if (artifacts.Errors != null && artifacts.Errors.Any())
					{
						foreach (var error in artifacts.Errors)
						{
							errorProvider.AddTask(new ErrorTask
							{
								CanDelete = true,
								ErrorCategory = TaskErrorCategory.Error,
								Text = error.Description
							});
							if(outputPaneLogger != null)
							{
								outputPaneLogger
									.Log("There was an error building your NHibernate configuration: {0}\n", 
										error.Description);

								
							}
						}
						continue;
					}
					if (artifacts.ClassInformation.Any())
					{
						classes = ConfigurationHelper.CombineClassInformation(classes, artifacts.ClassInformation);
					}
					if (artifacts.Imports != null && artifacts.Imports.Any())
					{
						imports = ConfigurationHelper.CombineImports(imports, artifacts.Imports);
					}	
				}catch(Exception ex)
				{
					if(outputPaneLogger != null)
					{
						var message = string.Format(
							"Exception Type:\t{0}\nException Message:\t{1}\nStackTrace:\t{2}\n\n",
							ex.GetType().Name,
							ex.Message,
							ex.StackTrace);
						outputPaneLogger.Log(message);
					}
				}
			}
		}

		[Import]
		public IOutputPaneLogger Logger { get; set;}

		public void Dispose()
		{
			errorProvider.Clear();
			errorProvider.Dispose();
		}
	}
}